package com.thinkit.bigdata.core.util.ssh;

import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.ServerHostKeyVerifier;
import ch.ethz.ssh2.Session;
import ch.ethz.ssh2.StreamGobbler;
import org.apache.log4j.Logger;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by BanAiQin on 2017/10/25.
 * SSH连接相关的方法
 */
public class SSHUtil {

    private static Logger logger = Logger.getLogger(SSHUtil.class);

    private Connection conn;
    private Session session;
    private String ip;
    private String userName;
    private String password;
    private String logTxt = "【SSH连接】";
    private boolean isAuth = false;//是否连接成功

    public SSHUtil(String ip, String userName, String password, String logTxt) {
        this.ip = ip;
        this.userName = userName;
        this.password = password;
        this.logTxt = logTxt;
        logger.info(logTxt + "ip=" + ip);
        logger.info(logTxt + "userName=" + userName);
        logger.info(logTxt + "password=");
        logger.info(logTxt + "logTxt=" + logTxt);
        logger.info(logTxt + "准备建立连接，ip=" + ip);
        this.isAuth = openConnection();//直接建立连接，并打开一个会话
    }

    public static void main(String[] args) {

    }

    public Session getSession() {
        if (isAuth) {
            try {
                session = conn.openSession();
            } catch (IOException e) {
                e.printStackTrace();
            }
            logger.info(logTxt + "已打开session");
        }
        return session;
    }

    /**
     * 打开一个SSH连接
     *
     * @return
     */
    public boolean openConnection() {
//                1.  首先构造一个连接器，传入一个需要登陆的ip地址
        conn = new Connection(ip);
//                2.  模拟登陆目的服务器 传入用户名和密码 ，
        try {
            conn.connect(new ServerHostKeyVerifier() {
                @Override
                public boolean verifyServerHostKey(String s, int i, String s1, byte[] bytes) throws Exception {
                    return true;
                }
            });
            isAuth = conn.authenticateWithPassword(userName, password);
//            3.  打开一个session，执行linux 脚本命令 。
            if (isAuth) {
//                session = conn.openSession();
                logger.info(logTxt + "已连接至" + ip);
            } else {
                logger.info(logTxt + "建立连接失败，ip=" + ip);
            }
        } catch (IOException e) {
            e.printStackTrace();
            logger.info(logTxt + "建立连接失败，ip=" + ip);
        }
        return isAuth;
    }

    /**
     * 关闭session和connection
     */
    public void closeConnection() {
        if (session != null) {
            session.close();
            session = null;
            logger.info(logTxt + "已关闭session");
        }
        if (conn != null) {
            conn.close();
            session = null;
            logger.info(logTxt + "断开连接，ip=" + ip);
        }
    }

    /**
     * 执行linux命令，返回值为boolean
     *
     * @param logTxt
     * @param command
     */
    public boolean execLinux(String logTxt, String... command) {
        logger.info(logTxt + "开始执行远程linux命令");
        boolean res = false;
        try {
            session = conn.openSession();
            if (session != null) {
                logger.info(logTxt + "打开session");
                for (String c : command) {
                    logger.info(logTxt + "[command in] " + c);
                    session.execCommand(c);
                }
                //接收目标服务器上的控制台返回结果，读取reader中的内容
                InputStream stdout = new StreamGobbler(session.getStdout());
                BufferedReader reader = new BufferedReader(new InputStreamReader(stdout));
                String line;
                while ((line = reader.readLine()) != null) {
                    logger.info(logTxt + "[command out] " + line);
                }
                reader.close();
                stdout.close();

                //得到脚本运行成功与否的标志 ：0－成功 非0－失败
                Integer status = session.getExitStatus();
                logger.info(logTxt + "ExitCode: " + session.getExitStatus());
                if (status != null && status == 0)
                    res = true;
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(logTxt + "执行命令出现异常");
            res = false;
        } finally {
            if (session != null) {
                session.close();
                logger.info(logTxt + "已关闭session");
            }
            logger.info(logTxt + "执行远程linux命令结束");
        }
        return res;
    }


    /**
     * 执行linux命令，返回值为 List<String>
     *
     * @param logTxt
     * @param command
     */
    public List<String> execLinuxResult(String logTxt, String... command) {
        logger.info(logTxt + "开始执行远程linux命令");
        boolean res = false;
        List<String> list = new ArrayList<>();
        try {
            session = conn.openSession();
            if (session != null) {
                logger.info(logTxt + "打开session");
                for (String c : command) {
                    logger.info(logTxt + "[command in] " + c);
                    session.execCommand(c);
                }
                //接收目标服务器上的控制台返回结果，读取reader中的内容
                InputStream stdout = new StreamGobbler(session.getStdout());
                BufferedReader reader = new BufferedReader(new InputStreamReader(stdout));
                String line;
                while ((line = reader.readLine()) != null) {
                    logger.info(logTxt + "[command out] " + line);
                    list.add(line);
                }
                reader.close();
                stdout.close();

                //得到脚本运行成功与否的标志 ：0－成功 非0－失败
                Integer status = session.getExitStatus();
                logger.info(logTxt + "ExitCode: " + session.getExitStatus());
                if (status == null || status == 0)
                    res = true;
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(logTxt + "执行命令出现异常");
            res = false;
        } finally {
            if (session != null) {
                session.close();
                logger.info(logTxt + "已关闭session");
            }
            logger.info(logTxt + "执行远程linux命令结束");
        }
        return list;
    }

    public boolean isAuth() {
        return isAuth;
    }

    public void setAuth(boolean auth) {
        isAuth = auth;
    }
}
